/**
 * 
 */
package com.nce.converter.audio;

import java.io.*;
import java.util.HashMap;

//import javax.media.control.*;
import javax.media.format.AudioFormat;

import com.nce.converter.TranscoderOutput;
import com.nce.protocol.rtp.NotAValidHeaderException;
import com.nce.protocol.rtp.ParticipantRTPStream;
import com.nce.protocol.rtp.RTPHeader;


import jpcap.JpcapCaptor;
import jpcap.packet.UDPPacket;
import jpcap.packet.Packet;


/**
 * @author domenico
 *
 */
public class Transcoder implements com.nce.converter.Transcoder
{

	private class InputPopulator extends Thread
	{
		public void run()
		{
			while(true)
			{
				Packet packet=captor.getPacket();
				  //if some error occurred or EOF has reached, break the loop
				if(packet==null || packet==Packet.EOF) break;
				  //otherwise, print out the packet
				if (packet instanceof UDPPacket)
				{
					try {
						UDPPacket udp = (UDPPacket)packet;
						RTPHeader header = new RTPHeader(udp.data);
						((ParticipantRTPStream)streams.get(header.ssrc)).addPacket(udp.data);
					} 
					catch (NotAValidHeaderException ex)
					{
						System.err.println("error in sending the data to the stream: \n" + ex);
						break;
					}
					catch (IOException ex)
					{
						System.err.println("error in sending the data to the stream: \n" + ex);
						break;
					}
			     }
			 }
			for (ParticipantRTPStream stream : streams.values())
			{
				stream.close();
			}
			captor.close();
		}
	}
	
	private class CodecEngine extends Thread
	{
		public void run()
		{
			boolean isAtLeastOneAlive = false;
			do
			{
				isAtLeastOneAlive = false;
				for (CodecWrapper codec : wrappers)
				{
					isAtLeastOneAlive |= codec.decodePacket();
				}
			} while (isAtLeastOneAlive);
		}
		
	}
	
	private HashMap<Integer, Long> offsets = null;
	private HashMap<Integer, ParticipantRTPStream> streams = null;
	
	private CodecWrapper[] wrappers;
	
	private boolean inited = false;
	private JpcapCaptor captor = null;
	private String strInputFile = null;
	private CodecEngine engine = null;
	
	private InputPopulator populator = null;
	
	@SuppressWarnings("unchecked")
	public boolean init(HashMap<String, Object> configMap)
	{
		int nStreams = -1;
		AudioFormat format = null;
		if (configMap.containsKey("input.streams_number"))
		{
			nStreams = (Integer)configMap.get("input.streams_number");
		}
		if (configMap.containsKey("input.audio.encoding"))
		{
			format = new AudioFormat((String)configMap.get("input.audio.encoding"));
		}
		if (configMap.containsKey("input.file.name"))
		{
			strInputFile = (String)configMap.get("input.file.name");
		}
		if (nStreams > 0 && configMap.containsKey("input.ssrc_and_offset"))
		{
			Object o = configMap.get("input.ssrc_and_offset");
			if (o instanceof HashMap)
			{
				offsets = (HashMap<Integer,Long>)o;
				streams = new HashMap<Integer, ParticipantRTPStream>();
				wrappers = new CodecWrapper[nStreams];
				int index = 0;
				for (Integer ssrc : offsets.keySet())
				{
					ParticipantRTPStream stream = new ParticipantRTPStream(format);
					streams.put(ssrc, stream);
					long off = (Long)offsets.get(ssrc);
					wrappers[index] = new CodecWrapper(format, stream, off);
					index++;
				}
				inited = true;
			}
		}
		populator = new InputPopulator();
		engine = new CodecEngine();
		return inited;
	}
	
	
	
	public void startTranscoding()
	{
		try {
			captor = JpcapCaptor.openFile(strInputFile);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		populator.start();
		engine.start();
	}
	
	public boolean isTranscoding()
	{
		return populator.isAlive() && engine.isAlive();
	}
	
	
	public void waitForStop()
	{
		try {
			populator.join();
			engine.join();
		}
		catch (InterruptedException ex)
		{
			ex.printStackTrace();
		}
	}
	
	
	public TranscoderOutput[] getOutputs()
	{
		return wrappers;
	}
	
	
//	/**
//	 * @param args
//	 */
//	public static void main(String[] args) {
//		
//		String path = null;
//		try{
//	      path = System.getProperty("user.dir");
//	      path += File.separator;
//	      //System.out.print("Executing at =>"+executionPath.replace("\\", "/"));
//		}catch (Exception e){
//	      System.out.println("Exception caught ="+e.getMessage());
//	      return;
//		}
//		Transcoder t = new Transcoder();
//		long[] offsets = {0, 400, 16000, 16000};
//		Format f = new javax.media.format.AudioFormat(javax.media.format.AudioFormat.ULAW);
//		Session session = new Session(path + "temp.wav", 4, offsets, f);
//		
//		String [] fileNames = new String[]{new String(path + "rtp_minacce_1st_partecipant.pcap"),
//											new String(path + "rtp_minacce_2nd_partecipant.pcap"),
//											new String(path + "G711_PCM_1.pcap"),
//											new String(path + "G711_PCM_2.pcap"),};
//		
//		if (t.loadSession(session))
//		{
//			ParticipantRTPStream [] streams = t.getStreams();
//			populateStreams(streams, fileNames);
//			t.startTranscoding();
//		}
//		
//		System.exit(0);
//	}
//
//	public static void populateStreams(ParticipantRTPStream [] streams, String [] filesInput )
//	{
//		
//		//open a file to read saved packets
//		for (int i = 0; i < streams.length; i++)
//		{
//			JpcapCaptor captor;
//			try {
//				captor = JpcapCaptor.openFile(filesInput[i]);
//			} catch (IOException e) {
//				System.err.println("error in opening the file with jpcap captor: \n" + e);
//				return;
//			}
//	
//			while(true){
//			  //read a packet from the opened file
//			  Packet packet=captor.getPacket();
//			  //if some error occurred or EOF has reached, break the loop
//			  if(packet==null || packet==Packet.EOF) break;
//			  //otherwise, print out the packet
//			  if (packet instanceof UDPPacket)
//			  {
//				try {
//					streams[i].addPacket(((UDPPacket)packet).data);
//				} catch (IOException e) {
//					System.err.println("error in sending the data to the stream: \n" + e);
//					return;
//				}
//				catch (NotAValidHeaderException ex)
//				{
//					System.err.println("error in sending the data to the stream: \n" + ex);
//					return;
//				}
//			  }
//			}
//			streams[i].close();
//			captor.close();
//		}
//	}
//	

		

	
	
}
